import os
import sys
import time
import hashlib
import tkinter as tk
from tkinter import ttk
from itertools import chain
from datetime import datetime
from tkinter import filedialog
import tkinter.messagebox as msgbox


def delete_choose():
    # 删除确认
    result = msgbox.askquestion("选择", "是否删除多余重复文件？")
    if result == "yes":
        return True
    else:
        return False


def get_files(directory, file_list):
    # 获取文件夹下所有文件
    for root_1, dirs, files in os.walk(directory):
        for file in files:
            file_list.append(os.path.join(root_1, file))
    return file_list


def get_file_md5(fname):
    # 获取MD5
    m = hashlib.md5()  # 创建md5对象
    with open(fname, 'rb') as fobj:
        while True:
            data = fobj.read(4096)
            if not data:
                break
            m.update(data)  # 更新md5对象

    return m.hexdigest()  # 返回md5对象


def find_the_same_files(the_files_md5_dict):
    new_dict = {}

    for key, value in the_files_md5_dict.items():
        new_dict.setdefault(value, set()).add(key)
    the_same_file_list = []

    for key, value in new_dict.items():
        if len(value) > 1:
            the_same_file_list.append(value)

    return the_same_file_list


def delete_file(the_same_file_list):
    # 删除文件
    for s in the_same_file_list:
        file_path_list = list(s)
        for f in file_path_list[1:]:
            if os.path.exists(f):
                os.remove(f)
                if os.path.exists(f):
                    text.insert(tk.END, f"{f}，删除失败\n")
                else:
                    text.insert(tk.END, f"{f}，删除成功\n")
            else:
                text.insert(tk.END, f"{f}，不存在，删除失败\n")


def set_size(container):
    # 获取显示器屏幕尺寸
    screen_width = container.winfo_screenwidth()
    screen_height = container.winfo_screenheight()

    # 设置gui尺寸
    gui_width = int(screen_width / 4)
    gui_height = int(screen_height / 2)

    # 定位中心点
    center_x = int((screen_width - gui_width) / 2)
    center_y = int((screen_height - gui_height) / 2)

    # 设置位置，大小
    container.geometry(f'{gui_width}x{gui_height}+{center_x}+{center_y}')

    # 禁止修改窗口尺寸
    container.resizable(False, False)


def click_add_folder(text_widget):
    # 添加需要查重的文件夹
    folder_path = filedialog.askdirectory()
    text_widget.insert(tk.END, folder_path + '\n')
    # 判断添加文件夹是否成功，成功则保存文件夹，并激活相关按钮
    if folder_path != '':
        folder_set.add(folder_path)
        btn2.state(['!disabled'])
        btn3.state(['disabled'])
        btn4.state(['disabled'])


def start_find(folder_set):
    # 开始查重
    # 前置操作
    btn1.state(['disabled'])
    btn3.state(['disabled'])
    btn4.state(['disabled'])
    # 程序计时
    start_time = time.time()
    # 1，获取所有文件夹下的所有文件
    file_list = []
    file_set = set()
    for folder in folder_set:
        file_list = get_files(folder, file_list)
    # 2，获取所有文件的大小
    for file in file_list:
        file = file.replace("/", os.sep).replace("\\", os.sep)
        file_set.add(file)

    file_size_dict = {}

    for file in file_set:
        stats = os.stat(file)
        file_size = stats.st_size
        file_size_dict[file] = file_size

    # 3，找出相同大小的文件
    rev_multidict = {}
    for key, value in file_size_dict.items():
        rev_multidict.setdefault(value, set()).add(key)

    the_same_size_files = set(
        chain.from_iterable(values for key, values in rev_multidict.items() if len(values) > 1))

    # 4，对相同大小的文件求MD5
    the_files_md5_dict = {}
    for file in the_same_size_files:
        file_md5 = get_file_md5(file)
        the_files_md5_dict[file] = file_md5

    # 5，找出相同MD5的文件
    global the_same_file_list
    the_same_file_list = find_the_same_files(the_files_md5_dict)

    for i in range(len(the_same_file_list)):
        text.insert(tk.END, f'第{i + 1}批重复文件如下：\n')
        for j in iter(the_same_file_list[i]):
            text.insert(tk.END, j + '\n')

    # 程序计时
    end_time = time.time()
    text.insert(tk.END, "程序结束，耗时：{:.2f}秒\n".format(end_time - start_time))
    # 后续操作
    btn3.state(['!disabled'])
    btn4.state(['!disabled'])
    folder_set.clear()

    return the_same_file_list


def create_start_frame(container, text_widget):
    frame = ttk.Frame(container)

    btn1 = ttk.Button(frame, text='添加文件夹', command=lambda: click_add_folder(text_widget))
    btn1.place(relx=0, rely=0, relwidth=0.5, relheight=1)

    btn2 = ttk.Button(frame, text='开始查重', command=lambda: start_find(folder_set))
    btn2.place(relx=0.5, rely=0, relwidth=0.5, relheight=1)
    btn2.state(['disabled'])

    return frame, btn1, btn2


def create_text_frame(container):
    frame = ttk.Frame(container)
    text_widget = tk.Text(frame, font=('Arial', 15))
    text_widget.place(relx=0, rely=0, relwidth=1, relheight=1)
    text_widget.insert('1.0', '请点击添加文件夹按钮，添加你需要查重的文件夹。\n')
    text_widget.insert(tk.END, '您添加的文件夹如下：\n')

    return frame, text_widget


def click_delete_file(the_same_file_list):
    # 删除文件
    if len(the_same_file_list) > 0:
        flag = delete_choose()
        if flag:
            delete_file(the_same_file_list)
    else:
        text.insert(tk.END, "没发现重复文件\n")

    return the_same_file_list.clear()


def create_end_frame(container):
    frame = ttk.Frame(container)

    btn3 = ttk.Button(frame, text='删除重复文件', command=lambda: click_delete_file(the_same_file_list))
    btn3.place(relx=0, rely=0, relwidth=0.25, relheight=1)
    btn3.state(['disabled'])

    btn4 = ttk.Button(frame, text='导出日志', command=export_log)
    btn4.place(relx=0.25, rely=0, relwidth=0.25, relheight=1)
    btn4.state(['disabled'])

    btn5 = ttk.Button(frame, text='重启软件', command=restart_program)
    btn5.place(relx=0.5, rely=0, relwidth=0.5, relheight=1)

    return frame, btn3, btn4


def restart_program():
    # 重启程序
    python = sys.executable
    os.execl(python, python, *sys.argv)


def export_log():
    # 导出日志
    # 选择保存日志的路径
    folder_path = filedialog.askdirectory()
    # 确定日志文件名
    file_name = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') + '-查重日志.txt'
    log_path = folder_path + os.sep + file_name
    # 日志内容
    text_content = text.get('1.0', 'end')
    # 写日志
    with open(log_path, 'w', encoding='utf-8') as f:
        f.write(text_content)


if __name__ == '__main__':
    root = tk.Tk()

    # 设置gui标题
    root.title('李氏文件查重')

    # 设置gui大小
    set_size(root)

    folder_set = set()

    text_frame, text = create_text_frame(root)
    text_frame.place(relx=0, rely=0.25, relwidth=1, relheight=0.5)

    start_frame, btn1, btn2 = create_start_frame(root, text)
    start_frame.place(relx=0, rely=0, relwidth=1, relheight=0.25)

    end_frame, btn3, btn4 = create_end_frame(root)
    end_frame.place(relx=0, rely=0.75, relwidth=1, relheight=0.25)

    root.mainloop()
